package ua.kpi_java_training.zabrodskyi.module3;

/**
 * The class describes behaviour of a victim in environment.
 * 
 * @author Maksym Zabrodskyi
 * @version 25-Jun-2013
 */
public class Victim extends Animal {

	private final int STEP = 1;
	private final int PERIOD_OF_SPAWN = 10;
	private int numberOfMovements = 0;

	/**
	 * Creates a victim in a cell in environment.
	 * 
	 * @param cell
	 *            in which the victim will be created.
	 */
	public Victim(Cell cell) {
		super(cell);
	}

	/**
	 * Describes algorithm of movement of a victim in environment.
	 */
	@Override
	public void move(Environment environment) {
		if (isPossibleMove(environment)) {
			setNewCell(environment);
			countMovement();
		}
	}

	/**
	 * Checks is possible movement of a victim.
	 * 
	 * @param environment
	 *            - environment in which the victim moves.
	 * 
	 * @return true if there is at least one step for movement, differently
	 *         false.
	 */
	private boolean isPossibleMove(Environment environment) {
		int x = this.getCell().getX();
		int y = this.getCell().getY();
		if (isCurrentLineEven()) {
			return isPossibleMoveFromEvenLine(environment, x, y);
		} else {
			return isPossibleMoveFromOddLine(environment, x, y);
		}
	}

	/**
	 * Whether check probably movement from an even line.
	 * 
	 * @param environment
	 *            - environment in which the victim moves.
	 * @param x
	 *            - coordinate x in which there is this victim.
	 * @param y
	 *            - coordinate y in which there is this victim.
	 * @return true if there is at least one step for movement, differently
	 *         false.
	 */
	private boolean isPossibleMoveFromEvenLine(Environment environment, int x,
			int y) {
		return environment.isFreeCell(new Cell(x + STEP, y))
				|| environment.isFreeCell(new Cell(x - STEP, y))
				|| environment.isFreeCell(new Cell(x, y - STEP))
				|| environment.isFreeCell(new Cell(x - STEP, y - STEP))
				|| environment.isFreeCell(new Cell(x, y + STEP))
				|| environment.isFreeCell(new Cell(x - STEP, y + STEP));
	}

	/**
	 * Whether check probably movement from an odd line.
	 * 
	 * @param environment
	 *            - environment in which the victim moves.
	 * @param x
	 *            - coordinate x in which there is this victim.
	 * @param y
	 *            - coordinate y in which there is this victim.
	 * @return true if there is at least one step for movement, differently
	 *         false.
	 */
	private boolean isPossibleMoveFromOddLine(Environment environment, int x,
			int y) {
		return environment.isFreeCell(new Cell(x + STEP, y))
				|| environment.isFreeCell(new Cell(x - STEP, y))
				|| environment.isFreeCell(new Cell(x + STEP, y - STEP))
				|| environment.isFreeCell(new Cell(x, y - STEP))
				|| environment.isFreeCell(new Cell(x + STEP, y + STEP))
				|| environment.isFreeCell(new Cell(x, y + STEP));
	}

	/**
	 * Sets a new cell in a random direction.
	 * 
	 * @param environment
	 *            - environment in which the victim moves.
	 */
	private void setNewCell(Environment environment) {
		Cell newCell = new Cell();
		do {
			newCell.setCell(this.getCell());
			int x = newCell.getX();
			int y = newCell.getY();
			switch (Random.getDirection()) {
			case EAST:
				setNewCellInEast(newCell, x);
				break;
			case WEST:
				setNewCellInWest(newCell, x);
				break;
			case NORTH_EAST:
				setNewCellInNorthEast(newCell, x, y);
				break;
			case NORTH_WEST:
				setNewCellInNorthWest(newCell, x, y);
				break;
			case SOUTH_EAST:
				setNewCellInSouthEast(newCell, x, y);
				break;
			case SOUTH_WEST:
				setNewCellInSouthWest(newCell, x, y);
				break;
			default:
				break;
			}
		} while (newCell.isBad()
				|| environment.isSettleElement(ElementType.BARRIER, newCell));
		this.setCell(newCell);
	}

	/**
	 * Sets a new cell in a direction the east.
	 * 
	 * @param newCell
	 *            - cell which needs to be sets in a new direction.
	 * @param x
	 *            - coordinate x in which there is this victim.
	 */
	private void setNewCellInEast(Cell newCell, int x) {
		newCell.setX(x + STEP);
	}

	/**
	 * Sets a new cell in a direction the west.
	 * 
	 * @param newCell
	 *            - cell which needs to be sets in a new direction.
	 * @param x
	 *            - coordinate x in which there is this victim.
	 */
	private void setNewCellInWest(Cell newCell, int x) {
		newCell.setX(x - STEP);
	}

	/**
	 * Sets a new cell in a direction the north-east.
	 * 
	 * @param newCell
	 *            - cell which needs to be sets in a new direction.
	 * @param x
	 *            - coordinate x in which there is this victim.
	 * @param y
	 *            - coordinate y in which there is this victim.
	 */
	private void setNewCellInNorthEast(Cell newCell, int x, int y) {
		if (!isCurrentLineEven()) {
			newCell.setX(x + STEP);
		}
		newCell.setY(y - STEP);
	}

	/**
	 * Sets a new cell in a direction the north-west.
	 * 
	 * @param newCell
	 *            - cell which needs to be sets in a new direction.
	 * @param x
	 *            - coordinate x in which there is this victim.
	 * @param y
	 *            - coordinate y in which there is this victim.
	 */
	private void setNewCellInNorthWest(Cell newCell, int x, int y) {
		if (isCurrentLineEven()) {
			newCell.setX(x - STEP);
		}
		newCell.setY(y - STEP);
	}

	/**
	 * Sets a new cell in a direction the south-east.
	 * 
	 * @param newCell
	 *            - cell which needs to be sets in a new direction.
	 * @param x
	 *            - coordinate x in which there is this victim.
	 * @param y
	 *            - coordinate y in which there is this victim.
	 */
	private void setNewCellInSouthEast(Cell newCell, int x, int y) {
		if (!isCurrentLineEven()) {
			newCell.setX(x + STEP);
		}
		newCell.setY(y + STEP);
	}

	/**
	 * Sets a new cell in a direction the south-west.
	 * 
	 * @param newCell
	 *            - cell which needs to be sets in a new direction.
	 * @param x
	 *            - coordinate x in which there is this victim.
	 * @param y
	 *            - coordinate y in which there is this victim.
	 */
	private void setNewCellInSouthWest(Cell newCell, int x, int y) {
		if (isCurrentLineEven()) {
			newCell.setX(x - STEP);
		}
		newCell.setY(y + STEP);
	}

	/**
	 * Checks, whether there is current cell on an even line.
	 * 
	 * @return returns true if current cell is on an even line, differently the
	 *         false.
	 */
	private boolean isCurrentLineEven() {
		return this.getCell().getY() % 2 == 0;
	}

	/**
	 * Increases quantity of movement of victim.
	 */
	private void countMovement() {
		numberOfMovements++;
	}

	/**
	 * Describes as the victim eats. A method empty as the technical project
	 * does not provide as a victim should eat.
	 */
	@Override
	public void eat(Environment environment) {
	}

	/**
	 * Describes as the victim breeds. If the victim has executed certain
	 * quantity of movement, the new victim is born.
	 * 
	 * * @param environment - environment in which the victim is it.
	 */
	@Override
	public void spawn(Environment environment) {
		if (numberOfMovements % PERIOD_OF_SPAWN == 0
				&& environment.hasFreeCell()) {
			environment.add(ElementType.VICTIM);
			Statistics.countSpawnedVictim();
			Statistics.addMessage("~ New Victim was born ~");
		}
	}

	/**
	 * Returns type of an element of this copy of a class.
	 * 
	 * @return type the Victim.
	 */
	@Override
	public ElementType getType() {
		return ElementType.VICTIM;
	}

}
